import json
import os

import numpy
import numpy as np
from ..PrintFormat.ColorPrint import RedPrint
import networkx as nx
import shutil


class SymbolVector:
    def __init__(self, root):
        self.project = os.path.join(root, "raw")
        # 1、输出符号边上的节点总数
        edge_file = os.path.join(self.project, "symboldep.mdg")
        edge = self._node(edge_file)
        RedPrint("symbol.mdg节点的数量：" + str(len(edge)))
        # 2、从vector中读出我们的符号的vector
        f = os.path.join(self.project, "symbolvectors.txt")
        self.symbol_vector, self.vector_dimension = self.ReadVector(f)
        RedPrint("符号vector的数量：" + str(len(self.symbol_vector)))
        RedPrint("符号vector的维度：" + str(self.vector_dimension))
        # 3、查看缺失的节点
        miss1, miss2 = self.miss(edge, self.symbol_vector)
        RedPrint("symboldep.mdg边上含有的节点中，没vector的节点的节点的数量：" + str(len(miss1)))
        # 4、查看所有的出边
        f = os.path.join(self.project, "symboldep.mdg")
        out = self.ListOfOutEdgeNode(f)
        # 5、查看所有边上缺失的节点中
        # 5.1、没有出边。
        # 5.2、出的边至少有一个有vector的。
        no_out_edge, outedge_has_vector = self.ListOfNoVectorNode(miss1, out, self.symbol_vector)

        # 6、将没有vector的节点删除之后，删除他们的边
        f = os.path.join(self.project, "symboldep.mdg")
        fout = os.path.join(self.project, "new_symboldep.mdg")
        self.ReBuildEdge(f, miss1, no_out_edge, outedge_has_vector, fout)
        # 7、计算这些没有vector的节点vector=出边的平均
        nodeVectorNodeHasOutnode = self.NodeVectorNodeHasOutnode(miss1, no_out_edge, outedge_has_vector, out,
                                                                 self.symbol_vector)

        RedPrint("边上的节点中，缺失vector的节点中没有出边的节点的数量：" + str(len(no_out_edge)))
        RedPrint(
            "边上的节点中，缺失vector的节点中出边的vector全为空的节点的的数量：" + str(len(miss1) - len(no_out_edge) - len(outedge_has_vector)))
        RedPrint("边上的节点中，缺失vector的节点中有出边，出边有vector的数量：" + str(len(outedge_has_vector)))

        # 8、合并到miss_vector
        self.symbol_vector.update(nodeVectorNodeHasOutnode)

        self.remove_noedge_node()

        RedPrint("节点总的数量：" + str(len(self.symbol_vector)))

        # 9、输出到文件中
        newsymbolvectors = os.path.join(self.project, "new_symbolvectors.txt")
        with open(newsymbolvectors, "w") as file:
            for key in self.symbol_vector.keys():
                file.write(str(key))
                for num in self.symbol_vector[key]:
                    file.write(" " + str(num))
                file.write("\n")

        # 10、输出json文件中
        filename = os.path.join(self.project, "new_symbolvectors.json")
        with open(filename, 'w') as file_obj:
            json.dump(self.symbol_vector, file_obj)

    def remove_noedge_node(self):
        tmp = []
        for node in self.symbol_vector.keys():
            if str(node) not in self.sub.nodes:
                tmp.append(node)

        for t in tmp:
            self.symbol_vector.pop(t)

    def getsymbolanddimension(self):
        return self.symbol_vector, self.vector_dimension

    def ReadVector(self, file):
        Symbol2Vector = {}
        with open(file, "r") as VectorFile:
            VectorLine = VectorFile.readlines()
            for Vector in VectorLine:
                Vectorid = int(Vector.split(" ")[0])
                vector = []
                for num in Vector.split(" ")[1:]:
                    vector.append(float(num))
                Symbol2Vector[Vectorid] = vector
                vectordimension = len(vector)
        return Symbol2Vector, vectordimension

    def _node(self, file):
        node = []
        with open(file, "r") as edgesfile:
            edges = edgesfile.readlines()
            for edge in edges:
                inedge = int(edge.split()[0])
                outedge = int(edge.split()[1])
                if inedge not in node:
                    node.append(inedge)
                if outedge not in node:
                    node.append(outedge)
        return node

    def miss(self, all, nodeveclist):
        miss1 = []
        miss2 = []
        for i in all:
            if i not in nodeveclist:
                miss1.append(i)
        for i in nodeveclist:
            if i not in all:
                miss2.append(i)
        return miss1, miss2

    def ListOfOutEdgeNode(self, file):
        outedges = {}
        with open(file, "r") as edgesfile:
            edges = edgesfile.readlines()
            for edge in edges:
                inedge = int(edge.split()[0])
                outedge = int(edge.split()[1])
                weight = int(edge.split()[2])
                if inedge not in outedges:
                    outedges[inedge] = [outedge]
                else:
                    outedges[inedge].append(outedge)
        return outedges

    def ListOfNoVectorNode(self, misses, out, vector):
        no_out_edge = []
        outedge_has_vector = []
        for miss in misses:
            if miss not in out:
                no_out_edge.append(miss)  # 没有出边的节点
            else:
                for outedge in out[miss]:
                    if outedge in vector:
                        outedge_has_vector.append(miss)
                        break
        return no_out_edge, outedge_has_vector

    def ReBuildEdge(self, fin, miss, no_out_edge, outedge_has_vector, fout):
        with open(fin, "r") as edgesfile:
            with open(fout, "w") as rebuild_edgefile:
                edges = edgesfile.readlines()
                for edge in edges:
                    inedge = int(edge.split()[0])
                    outedge = int(edge.split()[1])
                    if inedge not in miss and outedge not in miss:
                        rebuild_edgefile.write(str(inedge) + " " + str(outedge) + " 1\n")
                    elif inedge not in no_out_edge and outedge not in no_out_edge:
                        if inedge in outedge_has_vector and outedge in outedge_has_vector:
                            rebuild_edgefile.write(str(inedge) + " " + str(outedge) + " 1\n")
        ##################################################

        G = nx.DiGraph()
        with open(fout, "r")as fp:
            lines = fp.readlines()
            for line in lines:
                line = line.split("\n")[0]
                line = line.split()
                G.add_edge(line[0], line[1])
        self.H = G.to_undirected()
        RedPrint("最大的含有vector节点数" + str(len(self.H.nodes)))
        os.remove(fout)
        with open(fout, "w")as fp:
            for c in nx.connected_components(self.H):
                if len(c) > 200:
                    self.sub = self.H.subgraph(c)
                    RedPrint("最大的子图节点数" + str(len(self.sub.nodes)))
                    for u, v in self.sub.edges:
                        fp.writelines(str(u) + " " + str(v) + " 1\n")
        ################################################

    def NodeVectorNodeHasOutnode(self, misses, no_out_edge, outedge_has_vector, out, vector):
        missvector = {}
        for miss in misses:
            if miss not in no_out_edge and miss in outedge_has_vector:
                ve = []
                for outedge in out[miss]:
                    if vector.__contains__(outedge):
                        ve.append(vector[outedge])
                ve = np.mean(ve, axis=0)
                missvector[miss] = list(ve)
        return missvector
